package graphics.base;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;

import com.sun.corba.se.impl.ior.ByteBuffer;

public class ExploreSTL {

	/**
	 * 用于正数,因为负数存储是补码 第81~84四个字节
	 *
	 * @param lowFirstBytes
	 * @return
	 */
	public static int STLFaceNum(byte[] lowFirstBytes) {
		if (lowFirstBytes != null && lowFirstBytes.length == 4) {
			int a = lowFirstBytes[0] & (0xFF);// 防止低位转二进制后是变成负数
			int b = (lowFirstBytes[1] << 8) & (0xFFFF);
			int c = (lowFirstBytes[2] << 16) & (0xFFFFFF);
			int d = (lowFirstBytes[3] << 24) & (0xFFFFFFFF);
			return a + b + c + d;
		}
		return -1;
	}

	/**
	 * resolve binary stl file
	 *
	 * @param stlPath
	 * @return
	 */
	public static List<Triangle> parseBinary(String stlPath) {
		RandomAccessFile stl = null;
		try {
			stl = new RandomAccessFile(stlPath, "r");
			stl.seek(80);
			byte[] arr = { 0, 0, 0, 0 };
			stl.read(arr);
			int facetNum = STLFaceNum(arr);

			int dataOffset = 84;
			stl.seek(dataOffset);

			byte temp[] = { 0, 0, 0, 0 };
			List<Triangle> list = new ArrayList<Triangle>(facetNum);
			for (int face = 0; face < facetNum; face++) {
				Triangle tri = new Triangle();
				// 法向量12个字节
				stl.read(temp);
				tri.nx = BaseUtil.toFloat(temp);// 4
				stl.read(temp);
				tri.ny = BaseUtil.toFloat(temp);// 4
				stl.read(temp);
				tri.nz = BaseUtil.toFloat(temp);// 4

				// 顶点坐标36字节
				stl.read(temp);
				tri.x1 = BaseUtil.toFloat(temp);// x
				stl.read(temp);
				tri.y1 = BaseUtil.toFloat(temp);// y
				stl.read(temp);
				tri.z1 = BaseUtil.toFloat(temp);// z

				stl.read(temp);
				tri.x2 = BaseUtil.toFloat(temp);// x
				stl.read(temp);
				tri.y2 = BaseUtil.toFloat(temp);// y
				stl.read(temp);
				tri.z2 = BaseUtil.toFloat(temp);// z

				stl.read(temp);
				tri.x3 = BaseUtil.toFloat(temp);// x
				stl.read(temp);
				tri.y3 = BaseUtil.toFloat(temp);// y
				stl.read(temp);
				tri.z3 = BaseUtil.toFloat(temp);// z

				// color2字节
				// instead of above to skip color
				stl.skipBytes(2);

				list.add(tri);
			}
			stl.close();
			return list;

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	//
	// * 'Binary STL File format:
	// * '***************************************
	// * 'UINT8[80] – Header
	// * 'UINT32 – Number of triangles
	// * '
	// * 'foreach triangle
	// * 'REAL32[3] – Normal vector
	// * 'REAL32[3] – Vertex 1
	// * 'REAL32[3] – Vertex 2
	// * 'REAL32[3] – Vertex 3
	// * 'UINT16 – Attribute byte count
	// *'End
	public static void generateSTL(Data3D data3D, String savePath) {

		ByteBuffer bbf = new ByteBuffer(80);
		bbf.append(BaseUtil.STL_FILE_HEAD);

		File stl = new File(savePath);

		try {
			if (!stl.exists()) {
				stl.createNewFile();
			}
			FileOutputStream fos = new FileOutputStream(stl);
			DataOutputStream doutput = new DataOutputStream(fos);
			byte[] temp = new byte[4];

			doutput.write(bbf.toArray());// Header
			//
			int triNum = data3D.tris.size();
			BaseUtil.toBytesLowFirst(triNum, temp);
			doutput.write(temp);// Number of triangles

			byte[] attribute = new byte[2];

			for (int i = 0; i < data3D.tris.size(); i++) {

				Triangle tri = data3D.tris.get(i);
				tri.calculateNormal();
				// normal
				BaseUtil.toBytesLowFirst(tri.nx, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.ny, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.nz, temp);
				doutput.write(temp);

				BaseUtil.toBytesLowFirst(tri.x1, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.y1, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.z1, temp);
				doutput.write(temp);

				BaseUtil.toBytesLowFirst(tri.x2, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.y2, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.z2, temp);
				doutput.write(temp);

				BaseUtil.toBytesLowFirst(tri.x3, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.y3, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.z3, temp);
				doutput.write(temp);

				doutput.write(attribute);
			}
			doutput.close();
			fos.close();

		} catch (IOException e) {
			e.printStackTrace();
		}

		return;
	}

}
